package com.github.data_manage.controller

import cn.hutool.core.io.FastStringWriter
import com.github.data_manage.common.CommonPage
import com.github.data_manage.common.CommonResult
import com.github.data_manage.common.ResultCode
import com.github.data_manage.config.SystemException
import com.github.data_manage.dao.FundDao
import com.github.data_manage.dao.FundMeetingDao
import com.github.data_manage.dao.FundMeetingHistoryDao
import com.github.data_manage.domain.po.Fund
import com.github.data_manage.domain.po.FundDepthResearch
import com.github.data_manage.domain.po.FundMeeting
import com.github.data_manage.domain.po.FundMeetingHistory
import com.github.data_manage.domain.vo.FundMeetingPageParm
import com.github.data_manage.enum.FundMeetingType
import com.github.data_manage.service.FundAiUploadService
import com.github.data_manage.service.FundDeepResearchService
import com.github.data_manage.util.PageUtil
import freemarker.template.Template
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.persistence.criteria.Predicate
import org.springframework.core.env.Environment
import org.springframework.data.domain.Sort
import org.springframework.data.jpa.domain.Specification
import org.springframework.mail.javamail.JavaMailSender
import org.springframework.mail.javamail.MimeMessageHelper
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer
import java.math.BigDecimal
import java.math.RoundingMode
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter


/**
 * @author chenhainan
 * @since 2025-02-07 19:17
 */
@RestController
@Tag(name = "FundMeetingController", description = "基金会议管理")
@RequestMapping("/fundMeetings")
class FundMeetingController(
    private val fundMeetingDao: FundMeetingDao,
    private val mailSender: JavaMailSender,
    private val fundDao: FundDao,
    private val fundDeepResearchService: FundDeepResearchService,
    private val environment: Environment,
    private val freeMarkerConfigurer: FreeMarkerConfigurer,
    private val fundAiUploadService: FundAiUploadService,
    private val fundMeetingHistoryDao: FundMeetingHistoryDao
) {

    @PostMapping("/save")
    @Operation(description = "新增基金会议信息")
    fun addFundMeeting(@Validated @RequestBody fundMeeting: FundMeeting): CommonResult<String> {
        fundMeeting.meetingType = FundMeetingType.NORMAL.name
        val fund = fundDao.findById(fundMeeting.fundId).orElseThrow { SystemException("指定的基金信息不存在") }
        fundMeeting.createTime = LocalDateTime.now()
        fundMeetingDao.save(fundMeeting)
        Thread.startVirtualThread {
            sendEmail(fund, fundMeeting)
        }

        val condition = Specification<FundMeeting> { root, _, builder ->
            val conditions = mutableListOf<Predicate>()
            conditions.add(builder.equal(root.get<Any>("fundId"), fund.fundId ?: 0))
            return@Specification builder.and(*conditions.toTypedArray())
        }

        val allMeetings = fundMeetingDao.findAll(condition);

        // 计算 meetingRate
        val meetingRate: BigDecimal = if (allMeetings.size == 1) {
            allMeetings[0].score ?: BigDecimal(0)
        } else {
            val latestMeetingRate = allMeetings[0].score ?: BigDecimal(0)
            val otherMeetingsAverage =
                calculateAverageScore(allMeetings.subList(1, allMeetings.size).map { it.score ?: BigDecimal(0) })
            (latestMeetingRate.multiply(BigDecimal(0.5)))
                .add(otherMeetingsAverage?.multiply(BigDecimal(0.5)))
        }


        val fundId = fund.fundId ?: throw IllegalArgumentException("基金ID不能为空")

        // 查找基金深度研究记录
        val fundDepthResearch = fundDeepResearchService.findByFundId(fundId)

        // 更新或创建基金深度研究记录
        if (fundDepthResearch != null) {
            fundDepthResearch.meetingRate = meetingRate
            fundDeepResearchService.save(fundDepthResearch)
        } else {
            val newFundDepthResearch = FundDepthResearch(
                fundId = fundId,
                meetingRate = meetingRate
            )
            fundDeepResearchService.save(newFundDepthResearch)
        }
        fundMeetingHistoryDao.save(FundMeetingHistory.normalMeetingHistory(fundMeeting))
//        // 更新 fundDepthResearch 表中的 meetingRate
//        val fundDepthResearch = fundDeepResearchService.findByFundId(fund.fundId ?: throw IllegalArgumentException("基金ID不能为空"))
//        fundDepthResearch?.let {
//            it.meetingRate = meetingRate as BigDecimal?
//            fundDeepResearchService.save(it)
//        } ?: run {
//            val newFundDepthResearch = FundDepthResearch(fundId = fund.fundId!!, meetingRate = meetingRate)
//            fundDeepResearchService.save(newFundDepthResearch)
//        }

        return CommonResult.success(ResultCode.SUCCESS.message)
    }

    fun calculateAverageScore(scores: List<BigDecimal?>): BigDecimal? {
        // 过滤掉 null 值
        val nonNullScores = scores.filterNotNull()

        if (nonNullScores.isEmpty()) {
            return null
        }

        // 计算总和
        val sum = nonNullScores.reduce { acc, score -> acc.add(score) }

        // 计算平均值
        val average = sum.divide(BigDecimal(nonNullScores.size), 2, RoundingMode.HALF_UP)

        return average
    }

    @PutMapping("/update")
    @Operation(description = "修改基金会议信息")
    fun updateFundMeeting(@Validated @RequestBody fundMeeting: FundMeeting): CommonResult<String> {
        fundMeeting.meetingType = FundMeetingType.NORMAL.name

        fundMeetingDao.save(fundMeeting)

        val condition = Specification<FundMeeting> { root, _, builder ->
            val conditions = mutableListOf<Predicate>()
            conditions.add(builder.equal(root.get<Any>("fundId"), fundMeeting.fundId))
            return@Specification builder.and(*conditions.toTypedArray())
        }

        val allMeetings = fundMeetingDao.findAll(condition);

        // 计算 meetingRate
        val meetingRate: BigDecimal = if (allMeetings.size == 1) {
            allMeetings[0].score ?: BigDecimal(0)
        } else {
            val latestMeetingRate = allMeetings[0].score ?: BigDecimal(0)
            val otherMeetingsAverage =
                calculateAverageScore(allMeetings.subList(1, allMeetings.size).map { it.score ?: BigDecimal(0) })
            (latestMeetingRate.multiply(BigDecimal(0.5)))
                .add(otherMeetingsAverage?.multiply(BigDecimal(0.5)))
        }


        val fundId = fundMeeting.fundId

        // 查找基金深度研究记录
        val fundDepthResearch = fundDeepResearchService.findByFundId(fundId)

        // 更新或创建基金深度研究记录
        if (fundDepthResearch != null) {
            fundDepthResearch.meetingRate = meetingRate
            fundDeepResearchService.save(fundDepthResearch)
        } else {
            val newFundDepthResearch = FundDepthResearch(
                fundId = fundId,
                meetingRate = meetingRate
            )
            fundDeepResearchService.save(newFundDepthResearch)
        }

        return CommonResult.success(ResultCode.SUCCESS.message)
    }


    @PostMapping("/sendEmail")
    @Operation(description = "手动发送基金会议邮件")
    fun sendFundMeetingEmail(@Validated @RequestBody fundMeeting: FundMeeting): CommonResult<String> {
        val fund = fundDao.findById(fundMeeting.fundId).orElseThrow { SystemException("指定的基金信息不存在") }
        sendEmail(fund, fundMeeting)
        return CommonResult.success(ResultCode.SUCCESS.message)
    }

    @Operation(description = "基金会议信息详情")
    @GetMapping(value = ["/details"])
    fun getPersonDetailsById(@RequestParam id: Int): CommonResult<FundMeeting?> {
        return CommonResult.success(fundMeetingDao.findById(id).orElse(null))
    }

    @Operation(description = "删除基金会议信息")
    @DeleteMapping
    fun deleteById(@RequestParam id: Int): CommonResult<Unit> {
        fundMeetingDao.deleteById(id)
        return CommonResult.success(Unit)
    }

    @Operation(description = "基金会议列表")
    @PostMapping(value = ["/list"])
    fun getFundList(@Validated @RequestBody fundMeetingPageParam: FundMeetingPageParm): CommonResult<CommonPage<FundMeeting>> {

        val condition = Specification<FundMeeting> { root, _, builder ->
            val conditions = mutableListOf<Predicate>()
            if (fundMeetingPageParam.fundId != null) {
                conditions.add(builder.equal(root.get<Any>("fundId"), fundMeetingPageParam.fundId))
            }
            return@Specification builder.and(*conditions.toTypedArray())
        }
        val page = PageUtil.buildJpaPage<FundMeeting>(fundMeetingPageParam.pageNum, fundMeetingPageParam.pageSize)
            .withSort(Sort.by(Sort.Direction.DESC, "meetingTime"))


        return CommonResult.success(CommonPage.restPage(fundMeetingDao.findAll(condition, page)))
    }

    fun sendEmail(
        fund: Fund, fundMeeting: FundMeeting,
        fundMeetingType: FundMeetingType = FundMeetingType.NORMAL
    ) {

        val message = mailSender.createMimeMessage()
        val helper = MimeMessageHelper(message, true, "UTF-8")
        helper.setSubject("基金${fund.fundName}会议")
        val configuration = freeMarkerConfigurer.configuration
        val template: Template = configuration.getTemplate("email.ftl")

        val params = mapOf<String, Any>(
            Pair("persons", fundMeeting.persons),
            Pair("location", fundMeeting.location ?: ""),
            Pair(
                "meetingContent",
                if (fundMeetingType == FundMeetingType.AI_AFTER_MEETING) fundMeeting.aiMeetingDetails!! else fundMeeting.meetingDetails
            ),
            Pair("outPersons", fundMeeting.opponentPersons ?: ""),
            Pair("score", fundMeeting.score ?: BigDecimal(0)),
//            Pair("meetingScore", fundMeeting.meetingScore ?: BigDecimal(0)),
            Pair("comments", fundMeeting.comments ?: ""),
            Pair("meetingTime", DateTimeFormatter.ofPattern("yyyy-MM-dd").format(fundMeeting.meetingTime)),
            Pair("insertBy", fundMeeting.insertBy ?: ""),
            Pair("otter", fundMeeting.otter ?: ""),
        )
        helper.setText(FastStringWriter().use {
            template.process(params, it)
            return@use it.toString()
        }, true)

        helper.setTo(environment.getProperty("system.target-email-address", "1806632927@qq.com"))
        helper.setFrom(environment.getProperty("system.from-email-address", "funddatamanage@gmail.com"))
        mailSender.send(message)
    }


    @PostMapping("/beforeMeeting")
    @Operation(description = "生成会前纪要")
    fun beforeMeeting(@RequestParam fundId: Int): CommonResult<Boolean> {
        fundAiUploadService.beforeMeeting(fundDao.findById(fundId).orElseThrow { SystemException("基金不存在") })
        return CommonResult.success(true)
    }

    @PostMapping("/afterMeeting")
    @Operation(description = "生成会后纪要")
    fun afterMeeting(
        @RequestBody fundMeeting: FundMeeting
    ): CommonResult<Boolean> {
        fundAiUploadService.afterMeeting(
            fundDao.findById(fundMeeting.fundId).orElseThrow { SystemException("基金不存在") },
            fundMeeting
        )
        return CommonResult.success(true)
    }
}